﻿using CoreWCF;
using SD.Infrastructure.DTOBase;
using SlamDunk.MES.AppService.Maps;
using SlamDunk.MES.Domain.Entities.FoundationContext;
using SlamDunk.MES.Domain.IRepositories;
using SlamDunk.MES.Domain.Mediators;
using SlamDunk.MES.IAppService.DTOs.Inputs;
using SlamDunk.MES.IAppService.DTOs.Outputs.FoundationContext;
using SlamDunk.MES.IAppService.Interfaces;
using SlamDunk.ValueObjects.Enums;
using System;
using System.Collections.Generic;
using System.Linq;

namespace SlamDunk.MES.AppService.Implements
{
    /// <summary>
    /// 基础定义服务契约实现
    /// </summary>
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall, IncludeExceptionDetailInFaults = true)]
    public class FoundationContract : IFoundationContract
    {
        #region # 字段及构造器

        /// <summary>
        /// 仓储中介者
        /// </summary>
        private readonly RepositoryMediator _repMediator;

        /// <summary>
        /// 单元事务
        /// </summary>
        private readonly IUnitOfWorkMES _unitOfWork;

        /// <summary>
        /// 依赖注入构造器
        /// </summary>
        public FoundationContract(RepositoryMediator repMediator, IUnitOfWorkMES unitOfWork)
        {
            this._repMediator = repMediator;
            this._unitOfWork = unitOfWork;
        }

        #endregion


        //命令部分

        #region # 创建工厂模型 —— void CreateFacility(Guid? parentNodeId, string facilityNo...
        /// <summary>
        /// 创建工厂模型
        /// </summary>
        /// <param name="parentNodeId">上级节点Id</param>
        /// <param name="facilityNo">工厂模型编号</param>
        /// <param name="facilityName">工厂模型名称</param>
        /// <param name="facilityLevel">工厂模型层次</param>
        /// <param name="facilityType">工厂模型类型</param>
        /// <param name="description">描述</param>
        public void CreateFacility(Guid? parentNodeId, string facilityNo, string facilityName, FacilityLevel facilityLevel, FacilityType? facilityType, string description)
        {
            Facility parentNode = parentNodeId.HasValue
                ? this._unitOfWork.Resolve<Facility>(parentNodeId.Value)
                : null;
            Facility facility = new Facility(facilityNo, facilityName, facilityLevel, facilityType, description, parentNode);

            this._unitOfWork.RegisterAdd(facility);
            this._unitOfWork.Commit();
        }
        #endregion

        #region # 修改工厂模型 —— void UpdateFacility(Guid facilityId, string facilityName...
        /// <summary>
        /// 修改工厂模型
        /// </summary>
        /// <param name="facilityId">工厂模型Id</param>
        /// <param name="facilityName">工厂模型名称</param>
        /// <param name="description">描述</param>
        public void UpdateFacility(Guid facilityId, string facilityName, string description)
        {
            Facility facility = this._unitOfWork.Resolve<Facility>(facilityId);
            facility.UpdateInfo(facilityName, description);

            this._unitOfWork.RegisterSave(facility);
            this._unitOfWork.Commit();
        }
        #endregion

        #region # 删除工厂模型 —— void RemoveFacility(Guid facilityId)
        /// <summary>
        /// 删除工厂模型
        /// </summary>
        /// <param name="facilityId">工厂模型Id</param>
        public void RemoveFacility(Guid facilityId)
        {
            Facility facility = this._unitOfWork.Resolve<Facility>(facilityId);
            IList<Guid> relatedFacilityIds = facility.GetDeepNodeIds();

            this._unitOfWork.RegisterRemoveRange<Facility>(relatedFacilityIds);
            this._unitOfWork.Commit();
        }
        #endregion

        #region # 创建工位 —— void CreateWorkStation(string workStationNo, string workStationName...
        /// <summary>
        /// 创建工位
        /// </summary>
        /// <param name="workStationNo">工位编号</param>
        /// <param name="workStationName">工位名称</param>
        /// <param name="facilityId">工厂模型Id</param>
        /// <param name="description">描述</param>
        public void CreateWorkStation(string workStationNo, string workStationName, Guid? facilityId, string description)
        {
            WorkStation workStation = new WorkStation(workStationNo, workStationName, facilityId, description);

            this._unitOfWork.RegisterAdd(workStation);
            this._unitOfWork.Commit();
        }
        #endregion

        #region # 修改工位 —— void UpdateWorkStation(Guid workStationId, string workStationNo...
        /// <summary>
        /// 修改工位
        /// </summary>
        /// <param name="workStationId">工位Id</param>
        /// <param name="workStationNo">工位编号</param>
        /// <param name="workStationName">工位名称</param>
        /// <param name="facilityId">工厂模型Id</param>
        /// <param name="description">描述</param>
        public void UpdateWorkStation(Guid workStationId, string workStationNo, string workStationName, Guid? facilityId, string description)
        {
            WorkStation workStation = this._unitOfWork.Resolve<WorkStation>(workStationId);
            workStation.UpdateInfo(workStationNo, workStationName, facilityId, description);

            this._unitOfWork.RegisterSave(workStation);
            this._unitOfWork.Commit();
        }
        #endregion

        #region # 删除工位 —— void RemoveWorkStation(Guid workStationId)
        /// <summary>
        /// 删除工位
        /// </summary>
        /// <param name="workStationId">工位Id</param>
        public void RemoveWorkStation(Guid workStationId)
        {
            this._unitOfWork.RegisterRemove<WorkStation>(workStationId);
            this._unitOfWork.Commit();
        }
        #endregion

        #region # 创建计量单位组 —— void CreateMeasureUnitGroup(string groupNo, string groupName...
        /// <summary>
        /// 创建计量单位组
        /// </summary>
        /// <param name="groupNo">计量单位组编号</param>
        /// <param name="groupName">计量单位组名称</param>
        /// <param name="groupDescription">描述</param>
        /// <param name="measureUnitParams">计量单位参数模型集</param>
        public void CreateMeasureUnitGroup(string groupNo, string groupName, string groupDescription, IEnumerable<MeasureUnitParam> measureUnitParams)
        {
            #region # 验证

            measureUnitParams = measureUnitParams?.ToArray() ?? Array.Empty<MeasureUnitParam>();
            if (!measureUnitParams.Any())
            {
                throw new ArgumentNullException(nameof(measureUnitParams), "计量单位集不可为空！");
            }
            if (measureUnitParams.Count(x => x.isMaster) != 1)
            {
                throw new ArgumentOutOfRangeException(nameof(measureUnitParams), "主计量单位为有且只有一个！");
            }

            #endregion

            IEnumerable<MeasureUnit> measureUnits =
                from param in measureUnitParams
                select new MeasureUnit(param.unitNo, param.unitName, param.masterCoefficient, param.isMaster, param.sort, param.description);

            MeasureUnitGroup unitGroup = new MeasureUnitGroup(groupNo, groupName, groupDescription);
            unitGroup.SetMeasureUnits(measureUnits);

            this._unitOfWork.RegisterAdd(unitGroup);
            this._unitOfWork.Commit();
        }
        #endregion

        #region # 修改计量单位组 —— void UpdateMeasureUnitGroup(Guid measureUnitGroupId, string groupName...
        /// <summary>
        /// 修改计量单位组
        /// </summary>
        /// <param name="measureUnitGroupId">计量单位组Id</param>
        /// <param name="groupName">计量单位组名称</param>
        /// <param name="description">描述</param>
        /// <param name="measureUnitParams">计量单位参数模型集</param>
        public void UpdateMeasureUnitGroup(Guid measureUnitGroupId, string groupName, string description, IEnumerable<MeasureUnitParam> measureUnitParams)
        {
            #region # 验证

            measureUnitParams = measureUnitParams?.ToArray() ?? Array.Empty<MeasureUnitParam>();
            if (!measureUnitParams.Any())
            {
                throw new ArgumentNullException(nameof(measureUnitParams), "计量单位集不可为空！");
            }
            if (measureUnitParams.Count(x => x.isMaster) != 1)
            {
                throw new ArgumentOutOfRangeException(nameof(measureUnitParams), "主计量单位为有且只有一个！");
            }

            #endregion

            IEnumerable<MeasureUnit> measureUnits =
                from param in measureUnitParams
                select new MeasureUnit(param.unitNo, param.unitName, param.masterCoefficient, param.isMaster, param.sort, param.description);

            MeasureUnitGroup unitGroup = this._unitOfWork.Resolve<MeasureUnitGroup>(measureUnitGroupId);
            unitGroup.UpdateInfo(groupName, description);
            unitGroup.SetMeasureUnits(measureUnits);

            this._unitOfWork.RegisterSave(unitGroup);
            this._unitOfWork.Commit();
        }
        #endregion

        #region # 删除计量单位组 —— void RemoveMeasureUnitGroup(Guid measureUnitGroupId)
        /// <summary>
        /// 删除计量单位组
        /// </summary>
        /// <param name="measureUnitGroupId">计量单位组Id</param>
        public void RemoveMeasureUnitGroup(Guid measureUnitGroupId)
        {
            this._unitOfWork.RegisterRemove<MeasureUnitGroup>(measureUnitGroupId);
            this._unitOfWork.Commit();
        }
        #endregion


        //查询部分

        #region # 获取工厂模型列表 —— IEnumerable<FacilityInfo> GetFacilities(string keywords...
        /// <summary>
        /// 获取工厂模型列表
        /// </summary>
        /// <param name="keywords">关键字</param>
        /// <param name="facilityLevel">工厂模型层次</param>
        /// <param name="facilityType">工厂模型类型</param>
        /// <param name="parentNodeId">上级节点Id</param>
        /// <returns>工厂模型列表</returns>
        public IEnumerable<FacilityInfo> GetFacilities(string keywords, FacilityLevel? facilityLevel, FacilityType? facilityType, Guid? parentNodeId)
        {
            ICollection<Facility> facilitys = this._repMediator.FacilityRep.FindDeeply(keywords, facilityLevel, facilityType, parentNodeId);
            IEnumerable<FacilityInfo> facilityInfos = facilitys.Select(x => x.ToDTO());

            return facilityInfos;
        }
        #endregion

        #region # 获取根级工厂模型列表 —— IEnumerable<FacilityInfo> GetRootFacilities()
        /// <summary>
        /// 获取根级工厂模型列表
        /// </summary>
        /// <returns>工厂模型列表</returns>
        public IEnumerable<FacilityInfo> GetRootFacilities()
        {
            ICollection<Facility> facilitys = this._repMediator.FacilityRep.FindRoots();
            IEnumerable<FacilityInfo> facilityInfos = facilitys.Select(x => x.ToDTO());

            return facilityInfos;
        }
        #endregion

        #region # 分页获取工位列表 —— PageModel<WorkStationInfo> GetWorkStationsByPage(...
        /// <summary>
        /// 分页获取工位列表
        /// </summary>
        /// <param name="keywords">关键字</param>
        /// <param name="pageIndex">页码</param>
        /// <param name="pageSize">页容量</param>
        /// <returns>工位列表</returns>
        public PageModel<WorkStationInfo> GetWorkStationsByPage(string keywords, int pageIndex, int pageSize)
        {
            ICollection<WorkStation> workStations = this._repMediator.WorkStationRep.FindByPage(keywords, pageIndex, pageSize, out int rowCount, out int pageCount);

            IEnumerable<Guid> facilityIds = workStations.Where(x => x.FacilityId.HasValue).Select(x => x.FacilityId.Value);
            IDictionary<Guid, FacilityInfo> facilityInfos = this._repMediator.FacilityRep.Find(facilityIds).ToDictionary(x => x.Key, x => x.Value.ToDTO());

            IEnumerable<WorkStationInfo> workStationInfos = workStations.Select(x => x.ToDTO(facilityInfos));

            return new PageModel<WorkStationInfo>(workStationInfos, pageIndex, pageSize, pageCount, rowCount);
        }
        #endregion

        #region # 分页获取计量单位组列表 —— PageModel<MeasureUnitGroupInfo> GetMeasureUnitGroupsByPage(...
        /// <summary>
        /// 分页获取计量单位组列表
        /// </summary>
        /// <param name="keywords">关键字</param>
        /// <param name="pageIndex">页码</param>
        /// <param name="pageSize">页容量</param>
        /// <returns>计量单位组列表</returns>
        public PageModel<MeasureUnitGroupInfo> GetMeasureUnitGroupsByPage(string keywords, int pageIndex, int pageSize)
        {
            IEnumerable<MeasureUnitGroup> unitGroups = this._repMediator.MeasureUnitGroupRep.FindByPage(keywords, pageIndex, pageSize, out int rowCount, out int pageCount);
            IEnumerable<MeasureUnitGroupInfo> unitGroupInfos = unitGroups.Select(x => x.ToDTO());

            return new PageModel<MeasureUnitGroupInfo>(unitGroupInfos, pageIndex, pageSize, pageCount, rowCount);
        }
        #endregion

        #region # 分页获取计量单位列表 —— PageModel<MeasureUnitInfo> GetMeasureUnitsByPage(string keywords...
        /// <summary>
        /// 分页获取计量单位列表
        /// </summary>
        /// <param name="keywords">关键字</param>
        /// <param name="unitGroupId">计量单位组Id</param>
        /// <param name="isMaster">是否主计量单位</param>
        /// <param name="pageIndex">页码</param>
        /// <param name="pageSize">页容量</param>
        /// <returns>计量单位列表</returns>
        public PageModel<MeasureUnitInfo> GetMeasureUnitsByPage(string keywords, Guid? unitGroupId, bool? isMaster, int pageIndex, int pageSize)
        {
            ICollection<MeasureUnit> measureUnits = this._repMediator.MeasureUnitRep.FindByPage(keywords, unitGroupId, isMaster, pageIndex, pageSize, out int rowCount, out int pageCount);
            IEnumerable<MeasureUnitInfo> measureUnitInfos = measureUnits.Select(x => x.ToDTO());

            return new PageModel<MeasureUnitInfo>(measureUnitInfos, pageIndex, pageSize, pageCount, rowCount);
        }
        #endregion

        #region # 获取计量单位列表 —— IEnumerable<MeasureUnitInfo> GetMeasureUnits(Guid measureGroupId)
        /// <summary>
        /// 获取计量单位列表
        /// </summary>
        /// <param name="measureGroupId">计量单位组Id</param>
        /// <returns>计量单位列表</returns>
        public IEnumerable<MeasureUnitInfo> GetMeasureUnits(Guid measureGroupId)
        {
            ICollection<MeasureUnit> measureUnits = this._repMediator.MeasureUnitRep.FindByGroup(measureGroupId);
            IEnumerable<MeasureUnitInfo> measureUnitInfos = measureUnits.Select(x => x.ToDTO());

            return measureUnitInfos;
        }
        #endregion

        #region # 是否存在计量单位 —— bool ExistMeasureUnit(Guid? measureUnitId, string measureUnitNo)
        /// <summary>
        /// 是否存在计量单位
        /// </summary>
        /// <param name="measureUnitId">计量单位Id</param>
        /// <param name="measureUnitNo">计量单位编号</param>
        /// <returns>是否存在</returns>
        public bool ExistMeasureUnit(Guid? measureUnitId, string measureUnitNo)
        {
            return this._repMediator.MeasureUnitRep.Exist(measureUnitId, measureUnitNo);
        }
        #endregion
    }
}
